﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenTK.Audio.OpenAL;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using VIA;
using VIA.Integration;
using VIA.Integration.Automatics;
using VIA.Integration.Domain;
using VIA.RbacPassport;

namespace VIA.SiMoJi.Domain
{
    public interface IFoxconnMES : IAutomatic, IDevice
    {
        Task<RspStackData> StackIn(params string[] barcodes);
        Task<RspStackData> StackOut(params string[] barcodes);
        Task<RspStackData> StackLQ(params string[] barcodes);
    }

    public class FoxconnMES : Automatic, IFoxconnMES, IHasOption<FoxconnMESOption>, ISuportInitialization
    {
        HttpClient _httpClient;
        FoxconnMESOption _option;
        bool _isConnected;
        public bool IsConnected
        {
            get => _isConnected;
            set
            {
                _isConnected = value;
                IsConnectedChanged?.Invoke(this);
            }
        }
        public FoxconnMESOption Option
        {
            get => _option;
            set => _option = value;
        }

        public event Action<IDevice> IsConnectedChanged;
        #region Constructor
        public FoxconnMES()
        {
            _httpClient = new HttpClient();
        }
        #endregion
        public void Connect()
        {
            if (_isConnected) return;
            Ping ping = new Ping();
            try
            {
                if (Option.IsUseMES)
                {
                    PingReply pr = ping.Send(Option.IpAddress);
                    IsConnected = pr.Status == IPStatus.Success;
                }
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"{Name}连接异常:{ex.Message}");
            }
        }
        public void Disconnect()
        {
            if (_isConnected)
                IsConnected = false;
        }
        public async Task<RspStackData> StackIn(params string[] barcodes)
        {
            return await MESStack(0, barcodes);
        }
        public async Task<RspStackData> StackOut(params string[] barcodes)
        {
            return await MESStack(1, barcodes);
        }
        async Task<RspStackData> MESStack(int state, params string[] barcodes)
        {
            string name = state == 0 ? "进站" : "出站";
            string barcode = string.Join("|", barcodes);
            var rspStackData = new RspStackData();
            Logger.LogInformation($"条码[{barcode}{name}开始");
            try
            {
                string requestUri = GetString(_option.Uri, state.ToString(), barcodes.Where(x => !x.IsNullOrEmpty()).ToArray());
                Logger.LogInformation($"条码[{barcode}]{name}信息:{requestUri}");
                var response = await _httpClient.PostAsync(requestUri.ToString(), default);
                string responseString = await response.Content.ReadAsStringAsync();
                rspStackData.ReturnString = responseString;
                if (responseString.Contains("PSC_OK"))
                {
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ok };
                        Logger.LogInformation($"条码[{barcodeItem}]{name}成功:{responseString}");
                    }
                }
                else if (responseString.Contains("PSC_ERROR"))
                {
                    List<string> errorMsgList = new List<string>();
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        if (!barcodeItem.IsNullOrEmpty())//条码不为空
                        {
                            if (responseString.Contains(barcodeItem))//返回信息里面包含内容过MES异常条码
                            {
                                rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ng };
                                Logger.LogInformation($"条码[{barcodeItem}]{name}失败返回信息:{responseString}");
                            }
                            else
                            {
                                rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodes[i], Quality = Quality.Ok };
                                Logger.LogInformation($"条码[{barcodeItem}]{name}成功返回信息:{responseString}");
                            }
                        }
                        else//条码为空的
                        {
                            rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem };
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ng };
                        Logger.LogInformation($"条码[{barcodeItem}]{name}失败范围信息不含PSC_OK|PSC_ERROR:{responseString}");
                    }
                }
                Logger.LogInformation($"条码[{barcode}{name}结束{rspStackData.GetQuality().ToString().ToUpper()}");
            }
            catch (Exception ex)
            {
                Logger.LogError($"条码[{barcode}]{name}异常:{ex.Message}");
            }
            return rspStackData;
        }

        public async Task<RspStackData> StackLQ(params string[] barcodes)
        {
            string name = "LQ";
            string barcode = string.Join("|", barcodes);
            var rspStackData = new RspStackData();
            Logger.LogInformation($"条码[{barcode}{name}开始");
            try
            {
                string requestUri = GetLQString(_option.LQUri, barcodes.Where(x => !x.IsNullOrEmpty()).ToArray());
                Logger.LogInformation($"条码[{barcode}]{name}信息:{requestUri}");
                var response = await _httpClient.PostAsync(requestUri.ToString(), default);
                string responseString = await response.Content.ReadAsStringAsync();
                rspStackData.ReturnString = responseString;
                if (responseString.Contains("PSC_OK"))
                {
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ok };
                        Logger.LogInformation($"条码[{barcodeItem}]{name}成功:{responseString}");
                    }
                }
                else if (responseString.Contains("PSC_ERROR"))
                {
                    List<string> errorMsgList = new List<string>();
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        if (!barcodeItem.IsNullOrEmpty())//条码不为空
                        {
                            if (responseString.Contains(barcodeItem))//返回信息里面包含内容过MES异常条码
                            {
                                rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ng };
                                Logger.LogInformation($"条码[{barcodeItem}]{name}失败返回信息:{responseString}");
                            }
                            else
                            {
                                rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodes[i], Quality = Quality.Ok };
                                Logger.LogInformation($"条码[{barcodeItem}]{name}成功返回信息:{responseString}");
                            }
                        }
                        else//条码为空的
                        {
                            rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem };
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < barcodes.Count(); i++)
                    {
                        string barcodeItem = barcodes[i];
                        rspStackData.ItemDatas[i] = new RspStackItemData() { Barcode = barcodeItem, Quality = Quality.Ng };
                        Logger.LogInformation($"条码[{barcodeItem}]{name}失败范围信息不含PSC_OK|PSC_ERROR:{responseString}");
                    }
                }
                Logger.LogInformation($"条码[{barcode}{name}结束{rspStackData.GetQuality().ToString().ToUpper()}");
            }
            catch (Exception ex)
            {
                Logger.LogError($"条码[{barcode}]{name}异常:{ex.Message}");
            }
            return rspStackData;
        }
        string GetString(string requestUri, string status, params string[] barcodes)
        {
            var strBuilder = new StringBuilder();
            strBuilder.Append(requestUri);
            strBuilder.Append($"{Option.C.Key}={Option.C.Value}").Append("&");
            strBuilder.Append($"{Option.EMP.Key}={Option.EMP.Value}").Append("&");
            strBuilder.Append($"{Option.LINE.Key}={Option.LINE.Value}").Append("&");
            strBuilder.Append($"{Option.MACHINE.Key}={Option.MACHINE.Value}").Append("&");
            strBuilder.Append($"{Option.STATION.Key}={Option.STATION.Value}").Append("&");
            strBuilder.Append($"{Option.SCANTYPE.Key}={Option.SCANTYPE.Value}").Append("&");
            strBuilder.Append($"{Option.SN.Key}={string.Join(",", barcodes)}").Append("&");
            strBuilder.Append($"{Option.PCBLIST.Key}={Option.PCBLIST.Value}").Append("&");
            strBuilder.Append($"{Option.MODELNAME.Key}={Option.MODELNAME.Value}").Append("&");
            strBuilder.Append($"{Option.WO.Key}={Option.WO.Value}").Append("&");
            strBuilder.Append($"{Option.CARRIER.Key}={Option.CARRIER.Value}").Append("&");
            strBuilder.Append($"{Option.MOULD.Key}={Option.MOULD.Value}").Append("&");
            strBuilder.Append($"{Option.COVER.Key}={Option.COVER.Value}").Append("&");
            strBuilder.Append($"{Option.LOCATION.Key}={Option.LOCATION.Value}").Append("&");
            strBuilder.Append($"{Option.SYMPTOM.Key}={Option.SYMPTOM.Value}").Append("&");
            strBuilder.Append($"{Option.STATUS.Key}={status}").Append("&");
            strBuilder.Append($"{Option.PROP1.Key}={Option.PROP1.Value}").Append("&");
            strBuilder.Append($"{Option.PROP2.Key}={Option.PROP2.Value}").Append("&");
            strBuilder.Append($"{Option.PROP3.Key}={Option.PROP3.Value}").Append("&");
            strBuilder.Append($"{Option.PROP4.Key}={Option.PROP4.Value}").Append("&");
            strBuilder.Append($"{Option.PROP5.Key}={Option.PROP5.Value}");
            return strBuilder.ToString();
        }
        string GetLQString(string requestUri, params string[] barcodes)
        {
            var strBuilder = new StringBuilder();
            strBuilder.Append(requestUri);
            strBuilder.Append($"{Option.LQ_C.Key}={Option.LQ_C.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_LINE.Key}={Option.LQ_LINE.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_STATION.Key}={Option.LQ_STATION.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_MACHINE_NAME.Key}={Option.LQ_MACHINE_NAME.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_ASSET_NAME.Key}={Option.LQ_ASSET_NAME.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_MAC_ID.Key}={Option.LQ_MAC_ID.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_UPLOAD_TYPE.Key}={Option.LQ_UPLOAD_TYPE.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_SN.Key}={string.Join(",", barcodes)}").Append("&");
            strBuilder.Append($"{Option.LQ_LINE_PROPERTY.Key}={Option.LQ_LINE_PROPERTY.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_STATION_CHECK.Key}={Option.LQ_STATION_CHECK.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_CARRIER_SN.Key}={Option.LQ_CARRIER_SN.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_COVER_SN.Key}={Option.LQ_COVER_SN.Value}").Append("&");
            strBuilder.Append($"{Option.LQ_VERSION.Key}={Option.LQ_VERSION.Value}");
            return strBuilder.ToString();
        }
        public Task InitializeAsync()
        {
            Logger = Service.GetService<ILoggerFactory>().CreateLogger("MES");
            Option = Recipe.Get<FoxconnMESOption>(this.Id);
            return Task.CompletedTask;
        }
    }
}

[AddINotifyPropertyChangedInterface]
public class RspStackData
{
    public RspStackItemData[] ItemDatas { get; set; } = new RspStackItemData[7];
    public Quality GetQuality()
    {
        if (ItemDatas.Any(x => x == null))
        {
            return Quality.Ng;
        }
        if (ItemDatas.Any(x => x.Quality == Quality.Ng))
        {
            return Quality.Ng;
        }
        if (ItemDatas.All(x => x.Quality == Quality.None))
        {
            return Quality.None;
        }
        return Quality.Ok;
    }
    public string ReturnString { get; set; }
}

[AddINotifyPropertyChangedInterface]
public class RspStackItemData
{
    public Quality Quality { get; set; }
    public bool IsBarcode => !Barcode.IsNullOrEmpty();
    public string Barcode { get; set; }
}


